package main

import (
	"errors"
	"github.com/google/uuid"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"log"
	"math/rand"
	"time"
)

const (
	letters = "abcdefghijklmnopqrstuvwxyz"
)

type User struct {
	ID        uint `gorm:"primarykey"`
	Name      string
	CreatedAt time.Time
	UpdatedAt time.Time
}

// BeforeCreate 钩子函数，在创建之前调用，其他的都有
func (u *User) BeforeCreate(*gorm.DB) error {
	uid := uuid.New()
	u.ID = uint(uid.ID())
	if u.Name == "role" {
		return errors.New("invalid role name")
	}
	return nil
}

func main() {
	db, err := gorm.Open(mysql.New(mysql.Config{
		DSN:                       "root:123456@tcp(127.0.0.1:33306)/test1?charset=utf8mb4&parseTime=True&loc=Local", // DSN data source name
		DefaultStringSize:         256,                                                                               // string 类型字段的默认长度
		DisableDatetimePrecision:  true,                                                                              // 禁用 datetime 精度，MySQL 5.6 之前的数据库不支持
		DontSupportRenameIndex:    true,                                                                              // 重命名索引时采用删除并新建的方式，MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
		DontSupportRenameColumn:   true,                                                                              // 用 `change` 重命名列，MySQL 8 之前的数据库和 MariaDB 不支持重命名列
		SkipInitializeWithVersion: false,                                                                             // 根据当前 MySQL 版本自动配置
	}), &gorm.Config{
		CreateBatchSize: 100, // 也可以在这里指定每批大小
	})
	if err != nil {
		log.Println(err)
	}
	// 如果没有就创建表
	db.AutoMigrate(&User{})
	// 增
	db.Create(&User{Name: randName()})
	// 批量插入
	users := []User{{Name: randName()}, {Name: randName()}}
	//db.Create(&users)
	db.CreateInBatches(&users, 100) // 指定每批的数量

	// 查询, 第一条，默认主键升序，如果没有主键就按model的第一个字段排序
	db.First(&User{ID: 12})
	// 最后一条，默认主键升序
	db.Last(&User{ID: 15})
	// 获取一条，不排序
	result := db.Take(&User{ID: 16})
	// 以上都会返回错误
	//result.RowsAffected // 返回找到的记录数
	//result.Error        // returns error or nil
	// 检查 ErrRecordNotFound 错误
	errors.Is(result.Error, gorm.ErrRecordNotFound)

	// 用 find 比较好,不用判断错误，应该返回0个元素
	db.Find(&User{ID: 10})

	// 查找全部
	db.Find(&users) // select * from users

	// 条件查询
	user := User{}
	db.Where("name = ?", "jinzhu").Find(&user)
	// 感觉用结构体好一点，但是如果是零值就不会查询，比如 age=0，查不到age=0，建议用上面的或者用键值对
	db.Where(User{ID: 4}).Find(&user)

	// 选择字段
	db.Select("name", "age").Find(&user)

	// 排序
	db.Order("age desc, name").Find(&users)

	// SELECT * FROM users OFFSET 5 LIMIT 10;
	db.Limit(10).Offset(5).Find(&users)

	// 子查询
	db.Where("amount > (?)", db.Table("orders").Select("AVG(amount)")).Find(&users)
	// SELECT * FROM "orders" WHERE amount > (SELECT AVG(amount) FROM "orders");

	// 修改
	// 注意 当通过 struct 更新时，GORM 只会更新非零字段。
	// 如果您想确保指定字段被更新，你应该使用 Select 更新选定字段，或使用 map 来完成更新操作
	db.Update("name", &user)
	db.Updates(&users)

	// delete
	db.Delete(&User{ID: 10})
	// DELETE from emails where email LIKE "%jinzhu%";
	db.Delete(&User{}, "email LIKE ?", "%jinzhu%")

}

// 获取任意6位字母
func randName() string {
	l := len(letters)
	var name []byte
	for i := 0; i < 6; i++ {
		randNum := rand.Float64() * float64(l)
		name = append(name, letters[int(randNum)])
	}
	return string(name)
}
